package owg.util;

import java.util.Comparator;
import java.util.LinkedList;
import java.util.Queue;
import java.util.TreeSet;

public class InstanceList
{
	
	private TreeSet<EntityBase> list;
	private Queue<EntityBase> queue;
	
	private InstanceCondition stepCondition;
	private InstanceCondition renderCondition;
	
	public InstanceList() {
		list  = new TreeSet<>(new Comparator<EntityBase>() {
			public int compare(EntityBase o1, EntityBase o2) {
				if(o2.getDepth() > o1.getDepth())
					return 1;
				if(o2.getDepth() < o1.getDepth())
					return -1;
				if(o2.getID() != o1.getID())
					return o2.getID()>o1.getID()?1:-1;
					return 0;
			}
		});
		queue = new LinkedList<EntityBase>();
		stepCondition = null;
		renderCondition = null;
	}
	
	public EntityBase[] retrieve(){
		return queue.toArray(new EntityBase[]{});
	}
	
	void add(EntityBase e) {
		list.add(e);
	}
	
	void remove(EntityBase e) {
		list.remove(e);
	}
	
	public InstanceCondition getStepCondition()
	{
		return stepCondition;
	}
	public InstanceCondition getRenderCondition()
	{
		return renderCondition;
	}
	public void setStepCondition(InstanceCondition condition)
	{
		stepCondition = condition;
	}
	public void setRenderCondition(InstanceCondition condition)
	{
		renderCondition = condition;
	}
	
	public void step() {
		EntityBase e;
		enqueue(stepCondition);
		while((e = queue.poll()) != null) {
			if(!e.isDestroyed())
				e.beginStep();
		}
		enqueue(stepCondition);
		while((e = queue.poll()) != null) {
			if(!e.isDestroyed())
				e.step();
		}
		enqueue(stepCondition);
		while((e = queue.poll()) != null) {
			if(!e.isDestroyed())
				e.endStep();
		}
	}
	
	public void render() {
		for(EntityBase e : list)
		{
			if(e.isVisible() && (renderCondition == null || renderCondition.accept(e)))
				e.render();
			if(e.isDestroyed())
				throw new RuntimeException(e+" was destroyed during render pass");
		}
	}
	
	private void enqueue(InstanceCondition cond)
	{
		for(EntityBase e : list)
		{
			if(cond == null || cond.accept(e))
				queue.offer(e);
		}
	}
	
	public void destroyAll() {
		EntityBase e;
		enqueue(null);
		while((e = queue.poll()) != null) {
			if(!e.isDestroyed())
				e.destroy();
		}
	}
	
}
